<template>
	<view class="content">
		<button @click="ondecryptSignRenderjs">解密签名数据--</button>
		<text :prop="options" :change:prop="test.ondecryptSign">无内容</text>
		<!-- <text :prop="options" :change:prop="test.ongetSign">无内容</text> -->
		<button @click="test.ongetSign">解密签名数据</button>

		// <text :prop="options" :change:prop="test.onauthDecrypt">无内容</text>

		<button @click="conphantom">建立连接</button>

		<button @click="test.handleClick">点击</button>

		<button>发起签名</button>
		<button>发起转账</button>


		<view class="" style="width: 100%;height: 20px;">
			{{walletaddress}}
			{{signature}}
		</view>
		<view class="" style="height: 1px;background-color: red;">
			--
		</view>
	</view>
</template>



<script>
	export default {
		// 原先的script，这里被称为service层
		onShow() {
			this.options.phantomEncryptionPublicKey = uni.getStorageSync('phantomEncryptionPublicKey')
		},
		data() {
			return {
				privateKey: uni.getStorageSync('privateKey'),
				publicKey: uni.getStorageSync('publicKey'),
				info: '我是普通js数据',
				options: {
					publicKey: uni.getStorageSync('publicKey'),
					data: uni.getStorageSync('data'),
					nonce: uni.getStorageSync('nonce'),
					secretKey: uni.getStorageSync('privateKey'),
					session: '',
					phantomEncryptionPublicKey: uni.getStorageSync('phantomEncryptionPublicKey'),
					uni: uni
				},
				session: '',
				walletaddress: '',
				signature:'',
				callAuthDecryptSign: false
			}
		},
		methods: {
			authDecrypt() {

			},
			conphantom() {
				const appUrl = encodeURIComponent("http://cxc.firo.asia/#/"); // 用您的应用 URL 替换
				const encryptionPublicKey = uni.getStorageSync('publicKey'); // 替换为您的加密公钥
				const redirectLink = encodeURIComponent("hbuilder://pages/index/index"); // 用您的回调 URL 替换
				const phantomUrl =
					`https://phantom.app/ul/v1/connect?app_url=${appUrl}&dapp_encryption_public_key=${encryptionPublicKey}&redirect_link=${redirectLink}`;
				plus.runtime.openURL(phantomUrl); // 打开 Phantom 钱包进行连接	
			},
			changeOptionFn() {
				this.options = {
					// 这个地方我用时间戳来修改token，用于触发change，实际需要传递的数据是num
					token: Date.now(),
					num: Math.random()
				}
			},
			// 接收数据
			ondecryptSignRenderjs(data){
				console.log('ondecryptSignRenderjs');
				this.walletaddress = data.publicKey
				this.signature = data.signature
			},

			ongetSignRenderjs(reg) {
				let that = this
				if (reg) {
					// console.log(reg,'reg');
					const dapp_encryption_public_key = reg.dapp_encryption_public_key; // 替换为您的加密公钥
					// console.log(dapp_encryption_public_key, 'dapp_encryption_public_key');
					// const dapp_encryption_public_key = uni.getStorageSync('publicKey'); // 替换为您的加密公钥
					const nonce = reg.nonce;
					const redirect_link = 'hbuilder://pages/index/index';
					const payload = reg.payload;
					// console.log(reg.nonce, 'reg.nonce');
					uni.setStorageSync('message', reg.message)

					const phantomUrl =
						`https://phantom.app/ul/v1/signMessage?dapp_encryption_public_key=${dapp_encryption_public_key}&redirect_link=${redirect_link}&nonce=${nonce}&payload=${payload}`;
					that.callAuthDecryptSign = true
					plus.runtime.openURL(phantomUrl); // 打开 Phantom 钱包进行连接
				}
			},
			acceptDataFromRenderjs(data) {
				console.log('从renderjs中接收到的数据', data)
			},
			decryptedDataRenderjs(data) {
				// console.log(data, 'decryptedDataRenderjs');
				if (data.session) {
					this.options.session = data.session
					this.options.phantomEncryptionPublicKey = uni.getStorageSync('phantomEncryptionPublicKey'),
						this.session = data.session
					this.walletaddress = data.public_key
				}
			},
			saveKeyHandle(data) {
				console.log(data, 'data');
				console.log(data.data, '131');
				this.publicKey = data.data.publicKey
				this.privateKey = data.data.privateKey
				this.options.publicKey = data.data.publicKey
				this.options.secretKey = data.data.privateKey
				uni.setStorageSync('publicKey', data.data.publicKey)
				uni.setStorageSync('privateKey', data.data.privateKey)
			}
		}
	}
</script>

<script lang="renderjs" module="test">
	// import * as nacl from "tweetnacl";
	import nacl from "tweetnacl";
	// import * as bs58 from "bs58";
	import bs58 from 'bs58';
	// import foo from "bar"

	import {
		Buffer
	} from 'buffer'



	const dappKeyPair = nacl.box.keyPair();

	// 将字符串转换为 ArrayBuffer
	function stringToArrayBuffer(str) {
		const encoder = new TextEncoder();
		return encoder.encode(str).buffer;
	}

	// 将 ArrayBuffer 转换为字符串
	function arrayBufferToString(buffer) {
		const decoder = new TextDecoder();
		return decoder.decode(buffer);
	}

	/**
	 * 解密加密数据
	 * @param {string} data - 经过 Base58 编码的加密数据
	 * @param {string} nonce - 经过 Base58 编码的随机数（用于解密）
	 * @param {Uint8Array} sharedSecret - 共享密钥（由本地私钥和对方公钥生成）
	 * @returns {Object} - 解密后的 JSON 数据
	 * @throws {Error} - 如果共享密钥缺失或解密失败，则抛出错误
	 */
	const decryptPayload = (data, nonce, sharedSecret) => {
		if (!sharedSecret) throw new Error("missing shared secret");
		// 解码 Base58 编码的数据和随机数

		const decryptedData = nacl.box.open.after(bs58.decode(data), bs58.decode(nonce), sharedSecret);
		if (!decryptedData) {
			throw new Error("Unable to decrypt data");
		}
		// 将解密后的二进制数据转换为字符串，并解析为 JSON 对象

		return JSON.parse(Buffer.from(decryptedData).toString("utf8"));
	};
	/**
	 * 加密数据
	 * @param {Object} payload - 需要加密的 JSON 对象
	 * @param {Uint8Array} sharedSecret - 共享密钥（由本地私钥和对方公钥生成）
	 * @returns {[Uint8Array, Uint8Array]} - 返回随机数（nonce）和加密后的数据
	 * @throws {Error} - 如果共享密钥缺失，则抛出错误
	 */
	const encryptPayload = (payload, sharedSecret) => {
		if (!sharedSecret) throw new Error("missing shared secret");
		// 生成一个 24 字节的随机数（nonce），用于加密
		const nonce = nacl.randomBytes(24);
		// 使用共享密钥加密 JSON 数据

		const encryptedPayload = nacl.box.after(
			Buffer.from(JSON.stringify(payload)), // 转换 JSON 数据为 Buffer
			nonce, // 随机数
			sharedSecret // 共享密钥
		);
		// 返回 nonce 和加密后的数据
		return [nonce, encryptedPayload];
	};
	export default {
		data() {
			return {}
		},
		methods: {
			async ondecryptSign(newValue, oldValue, ownerInstance, instance) {
				console.log('ondecryptSign222222222');
				let nonce = newValue.nonce
				let data = newValue.data
				let secretKey = newValue.secretKey
				let publicKey = newValue.phantomEncryptionPublicKey
				const secretKeyArray = JSON.parse(JSON.stringify(secretKey));
				const secretKeyBuffer = Buffer.from(Object.values(secretKeyArray));
				const sharedSecretDapp = nacl.box.before(bs58.decode(publicKey), secretKeyBuffer);
				// console.log(nonce, 'nonce');
				const signMessageData = decryptPayload(
					data,
					nonce,
					sharedSecretDapp
				);
				ownerInstance.callMethod('ondecryptSignRenderjs', signMessageData)
			},
			async ongetSign(newValue, oldValue, ownerInstance, instance) {
				console.log('ongetSign');

				let session = newValue.session
				let secretKey = newValue.secretKey
				let publicKey = newValue.phantomEncryptionPublicKey
				console.log(session, 'session');
				console.log(secretKey, 'secretKey');
				console.log(publicKey, 'phantomEncryptionPublicKey');
				// return;
				const secretKeyArray = JSON.parse(JSON.stringify(secretKey));
				const secretKeyBuffer = Buffer.from(Object.values(secretKeyArray));
				// const secretKeyBuffer = Buffer.from(Object.values(secretKey));
				const sharedSecretDapp = nacl.box.before(bs58.decode(publicKey), secretKeyBuffer);
				const message = Date.now().toString();
				// const message = "To avoid digital dognappers, sign below to authenticate with CryptoCorgis.";
				const payload = {
					session,
					message: bs58.encode(Buffer.from(message)),
				};
				const [nonce, encryptedPayload] = encryptPayload(payload, sharedSecretDapp);
				console.log(encryptedPayload, 'encryptedPayload');
				const dataRes = {
					dapp_encryption_public_key: bs58.encode(dappKeyPair.publicKey),
					payload: bs58.encode(encryptedPayload),
					nonce: bs58.encode(nonce),
					message
				}
				ownerInstance.callMethod('ongetSignRenderjs', dataRes)
			},
			async onauthDecrypt(newValue, oldValue, ownerInstance, instance) {
				console.log('onauthDecrypt');
				// console.log('service层中的options发生变化')
				// console.log('新值', newValue)
				// console.log('旧值', oldValue)
				let phantomEncryptionPublicKey = newValue.phantomEncryptionPublicKey
				let nonce = newValue.nonce
				let data = newValue.data
				let secretKey = newValue.secretKey
				let uni = newValue.uni
				const secretKeyBuffer = Buffer.from(Object.values(secretKey));
				const sharedSecretDapp = nacl.box.before(bs58.decode(phantomEncryptionPublicKey), secretKeyBuffer);
				const decryptedData = decryptPayload(data, nonce, sharedSecretDapp);
				ownerInstance.callMethod('decryptedDataRenderjs', decryptedData)
			},
			async handleClick(event, ownerInstance) {
				console.log(uni, 'uniapp');
				console.log(ownerInstance, 'ownerInstance');
				const publicKey = bs58.encode(dappKeyPair.publicKey)
				const secretKey = dappKeyPair.secretKey
				const data = {
					publicKey: publicKey,
					privateKey: secretKey,
				}
				// 保存秘药
				ownerInstance.callMethod('saveKeyHandle', {
					data
				})
			},
			onChange(newValue, oldValue, ownerInstance, instance) {
				console.log('service层中的options发生变化')
				console.log('新值', newValue.num)
				console.log('旧值', oldValue.num)
				// ownerInstance和this.$ownerInstance一样，可用来向service层通信
				// instance和ownerInstance的区别是：
				// instance.$el指向的是触发事件的那个节点；ownerInstance.$el指向当前vue文件中的根节点；
				// instance的作用目前尚不明确，官方没有给出用法
			},
			onClick(event, ownerInstance) {
				ownerInstance.callMethod('acceptDataFromRenderjs', {
					content: '测试文字'
				})
				// 或this.$ownerInstance.callMethod('acceptDataFromRenderjs', { content: '测试文字' })
				// 需要注意的是：只有通过在template中用户手动操作触发renderjs的方法参数是这两个：event, ownerInstance；
				// 通过其他方法触发的函数参数不一样，后面会说
			}
		},
		created() {
			console.log('renderjs初始化完毕')
			// console.log(Connection,'Connection');
		}
	}
</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
</style>